﻿package core.drawing
{
    import __AS3__.vec.*;
    import core.enum.*;
    import core.image.*;
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;

    final public class RedEyeReductionTool extends Tool
    {
        private var mLeft:int;
        private var mTop:int;
        private var mRight:int;
        private var mBottom:int = 0;
        private var ranges:Vector.<Range>;
        private var pxchecked:Vector.<Boolean>;

        public function RedEyeReductionTool(param1:Tuyitu)
        {
            super(param1, ToolType.RedEyeReduction, false);
            return;
        }// end function

        override public function Reset() : void
        {
            type.attitude.locked = Boolean(ed.canvas.layer.type != LayerType.Bitmap);
            if (AppState.OnCanvas)
            {
                ed.cursor.Set(type);
            }
            ed.options.SetTool(type);
            return;
        }// end function

        override public function MouseDown(event:MouseEvent) : void
        {
            var _loc_2:BitmapData = null;
            var _loc_3:Point = null;
            var _loc_4:Object = null;
            var _loc_5:Number = NaN;
            if (!type.attitude.locked)
            {
                this.UpdateReferences();
                history.Prepare(Action.RedEyeReductionTool);
                _loc_2 = layer.activeBitmap;
                _loc_3 = canvas.GetOffsetMousePosition(layer.offset);
                if (_loc_2 != null)
                {
                    _loc_4 = this.FindMaxRedness(_loc_2, _loc_3);
                    if (_loc_4.max > 22)
                    {
                        _loc_5 = _loc_4.avg;
                        if (_loc_5 > 65)
                        {
                            _loc_5 = 65;
                        }
                        else if (_loc_5 < 40)
                        {
                            _loc_5 = 40;
                        }
                        _loc_5 = _loc_4.avg * (0.95 - (_loc_5 - (30 + 30 * (1 - options.tolerance))) / 100);
                        this.DoRedEye(_loc_2, _loc_4.loc, _loc_5);
                    }
                }
                canvas.UpdateAfterEdit();
                history.Commit();
            }
            return;
        }// end function

        public function FindMaxRedness(flash.events:BitmapData, flash.events:Point) : Object
        {
            var _loc_3:Number = NaN;
            var _loc_4:uint = 0;
            var _loc_9:int = 0;
            var _loc_10:int = 0;
            var _loc_11:int = 0;
            var _loc_5:* = new Rectangle(flash.events.x, flash.events.y);
            _loc_5.inflate(5, 5);
            _loc_5 = _loc_5.intersection(flash.events.rect);
            var _loc_6:* = new Point();
            var _loc_7:Number = 0;
            var _loc_8:Number = 0;
            _loc_10 = _loc_5.left;
            while (_loc_10 <= _loc_5.right)
            {
                
                _loc_11 = _loc_5.top;
                while (_loc_11 <= _loc_5.bottom)
                {
                    
                    _loc_4 = flash.events.getPixel(_loc_10, _loc_11);
                    _loc_3 = this.EvalRedness(_loc_4 >>> 16 & 255, _loc_4 >>> 8 & 255, _loc_4 & 255);
                    if (_loc_3 > _loc_7)
                    {
                        _loc_7 = _loc_3;
                        _loc_6.x = _loc_10;
                        _loc_6.y = _loc_11;
                    }
                    if (_loc_3 > 22)
                    {
                        _loc_8 = _loc_8 + _loc_3;
                        _loc_9++;
                    }
                    _loc_11++;
                }
                _loc_10++;
            }
            var _loc_12:* = new Object();
            _loc_12.max = _loc_7;
            _loc_12.loc = _loc_6;
            _loc_12.amt = _loc_9;
            _loc_12.avg = _loc_8 / _loc_9;
            return _loc_12;
        }// end function

        private function EvalRedness(loc:uint, loc:uint, loc:uint) : Number
        {
            var _loc_4:* = 1 / (loc + loc + loc);
            var _loc_5:* = this.RGBToLuminance(loc, loc, loc);
            var _loc_6:* = this.NormRGToRedness(loc * _loc_4, loc * _loc_4) * this.Sigmoid((_loc_5 / 255 - 0.15) * 20) * 255;
            if (_loc_6 < _loc_5 * 0.55)
            {
                return 0;
            }
            if (_loc_6 < 0)
            {
                return 0;
            }
            return _loc_6;
        }// end function

        private function RedTester(core.enum:uint, core.enum:Number) : Boolean
        {
            return Boolean(this.EvalRedness(core.enum >>> 16 & 255, core.enum >>> 8 & 255, core.enum & 255) > core.enum);
        }// end function

        private function NormRGToRedness(loc:Number, loc:Number) : Number
        {
            return (loc - 1 / 3) * 1.2 - (loc - 1 / 3) * 0.6;
        }// end function

        private function RGBToLuminance(loc:uint, loc:uint, loc:uint) : Number
        {
            return 0.2217 * loc + 0.707 * loc + 0.0713 * loc;
        }// end function

        private function Sigmoid(loc:Number) : Number
        {
            return 1 / (1 + Math.exp(-Math.max(Math.min(100, loc), -100)));
        }// end function

        private function DoRedEye(RedEyeReductionTool.as$381:BitmapData, RedEyeReductionTool.as$381:Point, RedEyeReductionTool.as$381:Number) : void
        {
            var _loc_4:* = new BitmapData(RedEyeReductionTool.as$381.width, RedEyeReductionTool.as$381.height, true);
            _loc_4.copyPixels(RedEyeReductionTool.as$381, RedEyeReductionTool.as$381.rect, RedEyeReductionTool.as$381.rect.topLeft);
            this.Fill(_loc_4, RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
            var _loc_5:* = new Rectangle(this.mLeft, this.mTop, this.mRight - this.mLeft + 1, this.mBottom - this.mTop + 1);
            var _loc_6:* = _loc_5.width / 4;
            var _loc_7:* = _loc_5.height / 4;
            _loc_6 = Math.max(_loc_6, 3);
            _loc_7 = Math.max(_loc_7, 3);
            _loc_5.inflate(_loc_6, _loc_7);
            _loc_5.intersection(_loc_4.rect);
            var _loc_8:* = new Point(0, 0);
            var _loc_9:* = new BitmapData(_loc_5.width, _loc_5.height, true, 0);
            _loc_9.threshold(_loc_4, _loc_5, _loc_8, "==", 0, 4278190080, 4278190080, false);
            _loc_9.applyFilter(_loc_9, _loc_9.rect, _loc_8, new BlurFilter(_loc_6, _loc_7));
            _loc_9.threshold(_loc_9, _loc_9.rect, _loc_8, ">", 0, 4278190080, 4278190080, false);
            _loc_9.applyFilter(_loc_9, _loc_9.rect, _loc_8, new BlurFilter(_loc_6, _loc_7));
            _loc_9.copyPixels(RedEyeReductionTool.as$381, _loc_5, _loc_8, _loc_9, _loc_8, false);
            this.AdjustRedeye(_loc_9);
            RedEyeReductionTool.as$381.copyPixels(_loc_9, _loc_9.rect, new Point(_loc_5.left, _loc_5.top), null, null, true);
            _loc_4.dispose();
            _loc_4 = null;
            return;
        }// end function

        private function AdjustRedeye(RedEyeReductionTool.as$381:BitmapData) : void
        {
            var _loc_2:uint = 0;
            var _loc_3:int = 0;
            var _loc_4:int = 0;
            var _loc_5:int = 0;
            var _loc_6:int = 0;
            var _loc_7:Number = NaN;
            var _loc_8:Number = NaN;
            var _loc_9:Number = NaN;
            var _loc_10:int = 0;
            var _loc_11:int = 0;
            while (_loc_10 < RedEyeReductionTool.as$381.width)
            {
                
                _loc_11 = 0;
                while (_loc_11 < RedEyeReductionTool.as$381.height)
                {
                    
                    _loc_2 = RedEyeReductionTool.as$381.getPixel32(_loc_10, _loc_11);
                    _loc_3 = _loc_2 >>> 24 & 255;
                    if (_loc_3 > 0)
                    {
                        _loc_4 = _loc_2 >>> 16 & 255;
                        _loc_5 = _loc_2 >>> 8 & 255;
                        _loc_6 = _loc_2 & 255;
                        _loc_7 = _loc_3 / 256;
                        _loc_8 = 1 - _loc_7;
                        _loc_9 = Math.min(_loc_4, _loc_5, _loc_5) * _loc_7;
                        _loc_4 = _loc_9 + _loc_8 * Math.min(_loc_5, _loc_4);
                        _loc_5 = _loc_9 + _loc_8 * _loc_4;
                        _loc_6 = _loc_9 + _loc_8 * _loc_6;
                        RedEyeReductionTool.as$381.setPixel(_loc_10, _loc_11, _loc_4 << 16 | _loc_5 << 8 | _loc_6);
                    }
                    _loc_11++;
                }
                _loc_10++;
            }
            return;
        }// end function

        public function Fill(RedEyeReductionTool.as$381:BitmapData, RedEyeReductionTool.as$381:Point, RedEyeReductionTool.as$381:Number) : void
        {
            var _loc_4:Range = null;
            var _loc_5:int = 0;
            this.mLeft = 99999;
            this.mTop = 99999;
            this.mRight = 0;
            this.mBottom = 0;
            var _loc_6:* = RedEyeReductionTool.as$381.width;
            var _loc_7:* = RedEyeReductionTool.as$381.height;
            this.ranges = new Vector.<Range>;
            this.pxchecked = new Vector.<Boolean>(_loc_6 * _loc_7, true);
            this.LinearFill(RedEyeReductionTool.as$381.x, RedEyeReductionTool.as$381.y, RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
            while (this.ranges.length > 0)
            {
                
                _loc_4 = this.ranges.shift();
                _loc_5 = _loc_4.start;
                while (_loc_5 < (_loc_4.stop + 1))
                {
                    
                    if (_loc_4.row > 0 && !this.pxchecked[(_loc_4.row - 1) * _loc_6 + _loc_5] && this.RedTester(RedEyeReductionTool.as$381.getPixel32(_loc_5, (_loc_4.row - 1)), RedEyeReductionTool.as$381))
                    {
                        this.LinearFill(_loc_5, (_loc_4.row - 1), RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
                    }
                    if (_loc_4.row < (_loc_7 - 1) && !this.pxchecked[(_loc_4.row + 1) * _loc_6 + _loc_5] && this.RedTester(RedEyeReductionTool.as$381.getPixel32(_loc_5, (_loc_4.row + 1)), RedEyeReductionTool.as$381))
                    {
                        this.LinearFill(_loc_5, (_loc_4.row + 1), RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
                    }
                    _loc_5++;
                }
            }
            return;
        }// end function

        private function LinearFill(RedEyeReductionTool.as$381:int, RedEyeReductionTool.as$381:int, RedEyeReductionTool.as$381:Number, RedEyeReductionTool.as$381:BitmapData) : void
        {
            var _loc_5:* = RedEyeReductionTool.as$381;
            var _loc_6:* = RedEyeReductionTool.as$381;
            var _loc_7:* = RedEyeReductionTool.as$381.width;
            while (true)
            {
                
                this.SetPixelPosition(_loc_5, RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
                this.pxchecked[_loc_7 * RedEyeReductionTool.as$381 + _loc_5] = true;
                _loc_5 = _loc_5 - 1;
                if (_loc_5 < 0 || this.pxchecked[_loc_7 * RedEyeReductionTool.as$381 + _loc_5] || !this.RedTester(RedEyeReductionTool.as$381.getPixel32(_loc_5, RedEyeReductionTool.as$381), RedEyeReductionTool.as$381))
                {
                    break;
                }
            }
            while (true)
            {
                
                this.SetPixelPosition(_loc_6, RedEyeReductionTool.as$381, RedEyeReductionTool.as$381);
                this.pxchecked[_loc_7 * RedEyeReductionTool.as$381 + _loc_6] = true;
                _loc_6++;
                if (_loc_6 >= _loc_7 || this.pxchecked[_loc_7 * RedEyeReductionTool.as$381 + _loc_6] || !this.RedTester(RedEyeReductionTool.as$381.getPixel32(_loc_6, RedEyeReductionTool.as$381), RedEyeReductionTool.as$381))
                {
                    break;
                }
            }
            var _loc_8:* = new Range((_loc_5 + 1), (_loc_6 - 1), RedEyeReductionTool.as$381);
            this.ranges.push(_loc_8);
            return;
        }// end function

        private function SetPixelPosition(RedEyeReductionTool.as$381:int, RedEyeReductionTool.as$381:int, RedEyeReductionTool.as$381:BitmapData) : void
        {
            if (RedEyeReductionTool.as$381 < this.mLeft)
            {
                this.mLeft = RedEyeReductionTool.as$381;
            }
            if (RedEyeReductionTool.as$381 > this.mRight)
            {
                this.mRight = RedEyeReductionTool.as$381;
            }
            if (RedEyeReductionTool.as$381 < this.mTop)
            {
                this.mTop = RedEyeReductionTool.as$381;
            }
            if (RedEyeReductionTool.as$381 > this.mBottom)
            {
                this.mBottom = RedEyeReductionTool.as$381;
            }
            RedEyeReductionTool.as$381.setPixel32(RedEyeReductionTool.as$381, RedEyeReductionTool.as$381, 0);
            return;
        }// end function

    }
}
